package com.adulcimer.services;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.adulcimer.models.dto.user.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.adulcimer.core.tools.DemonExceptionMessage;
import com.adulcimer.core.tools.DemonPagingModel;
import com.adulcimer.models.entity.domain.SRole;
import com.adulcimer.models.entity.domain.SUserRole;
import com.adulcimer.models.entity.domain.User;
import com.adulcimer.models.entity.service.SRoleService;
import com.adulcimer.models.entity.service.SUserRoleService;
import com.adulcimer.models.enums.AccountEnum;
import com.adulcimer.models.enums.CommonStatusEnum;
import com.adulcimer.models.entity.service.UserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.adulcimer.models.vo.RoleVo;
import com.adulcimer.models.vo.UserVo;
import io.micrometer.common.util.StringUtils;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author Simon
 * @create 2025/7/18
 * @Description
 **/

@Service
public class AccountService extends BaseService{

    @Resource
    private UserService userService;

    @Resource
    private SUserRoleService sUserRoleService;

    @Resource
    private SRoleService sroleService;
    /**
     * 登录
     */
    public String login(UserLoginDto userLoginDto){
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getAccount,userLoginDto.getAccount());
        User user = userService.getOne(queryWrapper);
        if(ObjectUtil.isEmpty(user)){
            throw new DemonExceptionMessage("账号不存在");
        }
        if(!BCrypt.checkpw(userLoginDto.getPassword(), user.getPassword())){
            throw new DemonExceptionMessage("账号或密码错误");
        }
        if(user.getStatus().equals(CommonStatusEnum.DISABLE.getValue())){
            throw new DemonExceptionMessage("账号已禁止使用");
        }
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(User::getId,user.getId());
        updateWrapper.set(User::getCount,user.getCount()+1);
        userService.update(updateWrapper);
        StpUtil.login(user.getId());
        return StpUtil.getTokenInfo().getTokenValue();
    }
    /**
     * 注销
     */
    public void logout(String token , String userId){
        StpUtil.logout(userId,token);
    }

    /**
     * 注册
     */
    public void sign(UserSignDto userSignDto){
        User user = new User();
        BeanUtils.copyProperties(userSignDto,user);
        if (StringUtils.isEmpty(userSignDto.getPassword())){
            throw new DemonExceptionMessage("密码不能为空");
        }
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getAccount, userSignDto.getAccount());
        if(userService.count(lambdaQueryWrapper) > 0){
            throw new DemonExceptionMessage("账号已存在");
        }
        user.setPassword(BCrypt.hashpw(userSignDto.getPassword()));
        user.setSysRole(AccountEnum.CUSTOMER.getValue());
        userService.save(user);
    }

    /**
     * 更改启用或禁用状态
     */
    public void enable(UserEnableDto userEnableDto){
        String string = userService.getById(getUserId()).getSysRole();
        if(!string.equals(AccountEnum.ADMIN.getValue())){
            throw new DemonExceptionMessage("当前用户无管理员权限");
        }
        if(userEnableDto.getId()==null){
            throw new DemonExceptionMessage("请选择用户");
        } else if(userEnableDto.getId().equals(getUserId())){
            throw new DemonExceptionMessage("不能禁用自己");
        }
        User one = userService.lambdaQuery().eq(User::getId, userEnableDto.getId()).one();
        if(ObjectUtil.isEmpty(one)){
            throw new DemonExceptionMessage("用户不存在");
        }else{
            one.setStatus(Objects.requireNonNull(CommonStatusEnum.getEnum(userEnableDto.getEnabled())).getValue());
            userService.updateById(one);
        }
    }

    public UserVo getByUserId(){
        User user = userService.getById(getUserId());
        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(user,userVo);
        return userVo;
    }

    public DemonPagingModel<List<UserVo>> list(Integer pageNumber, Integer pageSize, String keyword){
        Page<User> page = new Page<>(pageNumber, pageSize);
        Page<User> page1 = userService.lambdaQuery()
                .like(StringUtils.isNotEmpty(keyword), User::getAccount, keyword)
                .or()
                .like(StringUtils.isNotEmpty(keyword), User::getName, keyword)
                .page(page);
        List<User> records = page1.getRecords();

        // 如果没有用户记录，直接返回空结果
        if (CollUtil.isEmpty(records)) {
            return new DemonPagingModel<>(pageNumber, pageSize, page1.getTotal(), new ArrayList<>());
        }

        // 提取所有用户ID
        List<Long> userIds = records.stream()
                .map(User::getId)
                .filter(Objects::nonNull)
                .toList();

        // 获取用户角色关联关系
        List<SUserRole> userRoleList = new ArrayList<>();
        if (!CollUtil.isEmpty(userIds)) {
            userRoleList = sUserRoleService.lambdaQuery()
                    .in(SUserRole::getUserId, userIds)
                    .list();
        }

        // 提取所有角色ID
        List<Long> roleIds = userRoleList.stream()
                .map(SUserRole::getRoleId)
                .filter(Objects::nonNull)
                .toList();

        // 获取所有相关角色信息
        List<SRole> roleList = new ArrayList<>();
        if (!CollUtil.isEmpty(roleIds)) {
            roleList = sroleService.lambdaQuery()
                    .in(SRole::getId, roleIds)
                    .list();
        }

        // 构建角色ID到SRole对象的映射
        Map<Long, SRole> roleMap = roleList.stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toMap(SRole::getId, Function.identity(), (existing, replacement) -> existing));

        // 构建用户ID到角色ID列表的映射
        Map<Long, List<Long>> userRoleIdsMap = userRoleList.stream()
                .filter(userRole -> userRole.getUserId() != null && userRole.getRoleId() != null)
                .collect(Collectors.groupingBy(
                        SUserRole::getUserId,
                        Collectors.mapping(SUserRole::getRoleId, Collectors.toList())
                ));

        // 构建用户ID到RoleVo列表的映射
        Map<Long, List<RoleVo>> userRolesMap = new HashMap<>();
        for (Map.Entry<Long, List<Long>> entry : userRoleIdsMap.entrySet()) {
            Long userId = entry.getKey();
            List<Long> rIds = entry.getValue();

            List<RoleVo> roleVos = rIds.stream()
                    .filter(roleMap::containsKey)
                    .map(roleMap::get)
                    .map(role -> {
                        RoleVo roleVo = new RoleVo();
                        roleVo.setId(role.getId());
                        roleVo.setRoleName(role.getRoleName());
                        return roleVo;
                    })
                    .toList();

            userRolesMap.put(userId, roleVos);
        }

        // 转换User到UserVo
        List<UserVo> vos = records.stream().map(item -> {
            UserVo vo = new UserVo();
            BeanUtils.copyProperties(item, vo);

            // 设置用户的角色列表
            List<RoleVo> userRoles = userRolesMap.getOrDefault(item.getId(), new ArrayList<>());
            vo.setRoles(userRoles);

            return vo;
        }).toList();

        return new DemonPagingModel<>(pageNumber, pageSize, page1.getTotal(), vos);
    }

    @Transactional(rollbackFor = Exception.class)
    public void update(UserUpdateDto dto){
        User byId = userService.getById(dto.getId());
        List<Long> roleList = sUserRoleService.lambdaQuery()
                .eq(SUserRole::getUserId, dto.getId())
                .list().stream().map(SUserRole::getRoleId).toList();
        if (StrUtil.isNotEmpty(dto.getName()) && !byId.getName().equals(dto.getName())){
            userService.lambdaUpdate()
                    .eq(User::getId, dto.getId())
                    .set(User::getName, dto.getName())
                    .update();
        }
        if (StrUtil.isNotEmpty(dto.getSysRole())){
            userService.lambdaUpdate()
                    .eq(User::getId, dto.getId())
                    .set(User::getSysRole, dto.getSysRole())
                    .update();
        }
        if (CollUtil.isNotEmpty(dto.getRoleIds()) && !roleList.equals(dto.getRoleIds())){
            sUserRoleService.lambdaUpdate()
                    .eq(SUserRole::getUserId, dto.getId())
                    .remove();
            List<SUserRole> userRoles = new ArrayList<>();
            for (Long roleId : dto.getRoleIds()) {
                SUserRole userRole = new SUserRole();
                userRole.setUserId(dto.getId());
                userRole.setRoleId(roleId);
                userRole.setCreatedBy(getUserId());
                userRoles.add(userRole);
            }
            sUserRoleService.saveBatch(userRoles);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void delete(List<Long> ids){

        if (ids.contains(getAdminId())){
            throw new IllegalArgumentException("不能删除系统管理员");
        }
        sUserRoleService.remove(new QueryWrapper<SUserRole>().lambda()
                .in(SUserRole::getUserId, ids));
        userService.removeByIds(ids);
    }

    public void add(UserAddDto dto){
        User user = new User();
        BeanUtils.copyProperties(dto, user);
        user.setPassword(BCrypt.hashpw(dto.getPassword()));
        userService.save(user);
        if (CollUtil.isNotEmpty(dto.getRoleIds())) {
            List<SUserRole> objects = new ArrayList<>();
            dto.getRoleIds().forEach(roleId -> {
                SUserRole userRole = new SUserRole();
                userRole.setUserId(user.getId());
                userRole.setRoleId(roleId);
                userRole.setCreatedBy(getUserId());
                objects.add(userRole);
            });
            sUserRoleService.saveBatch(objects);
        }
    }


}
